堆排序是一种基于比较的排序算法，利用二叉堆的数据结构来实现。堆是一个完全二叉树，它满足一定的条件：每个节点的值都大于等于（或小于等于）其左右子节点的值。根据这个性质，堆排序使用堆的数据结构来维护待排序元素的序列，通过重复执行删除最大（或最小）元素的操作，得到一个有序序列。

- 堆排序的步骤如下：
  - 构建最大堆（或最小堆）：将待排序元素构建成一个堆，堆中每个节点的值都大于等于（或小于等于）其左右子节点的值。
  - 交换堆顶元素和最后一个元素：将堆顶元素与堆中最后一个元素交换位置，并把堆的大小减 1。
  - 对堆进行调整：从堆顶开始，将堆调整为最大堆（或最小堆）。
  - 重复执行步骤 2 和 3，直到堆中只剩一个元素。

```js
function heapSort(arr) {
  // 构建最大堆
  function buildHeap(arr, heapSize) {
    for (let i = Math.floor(heapSize / 2) - 1; i >= 0; i--) {
      heapify(arr, heapSize, i);
    }
  }

  // 调整堆
  function heapify(arr, heapSize, i) {
    let largest = i;
    let left = 2 * i + 1;
    let right = 2 * i + 2;

    if (left < heapSize && arr[left] > arr[largest]) {
      largest = left;
    }

    if (right < heapSize && arr[right] > arr[largest]) {
      largest = right;
    }

    if (largest !== i) {
      swap(arr, i, largest);
      heapify(arr, heapSize, largest);
    }
  }

  // 交换元素
  function swap(arr, i, j) {
    let temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }

  let heapSize = arr.length;

  buildHeap(arr, heapSize);

  // 交换堆顶元素和最后一个元素，并调整堆
  while (heapSize > 1) {
    swap(arr, 0, heapSize - 1);
    heapSize--;
    heapify(arr, heapSize, 0);
  }

  return arr;
}
```

:::info
这个实现是基于最大堆的排序，可以通过修改比较函数来实现最小堆排序。堆排序的时间复杂度为 O(nlogn)，空间复杂度为 O(1)。
:::